//
//  YHNetworkManager+Request.m
//  YHBaseProject
//
//  Created by yuhang liu on 2022/11/18.
//  Copyright © 2022 lyh. All rights reserved.
//

#import "YHNetworkManager+Request.h"
#import "YHAESHelper.h"
#import "YHRSAHelper.h"
#import "YHNetLogManager.h"

@implementation YHNetworkManager (Request)

- (void)postWithUrl:(NSString *)url
         parameters:(NSMutableDictionary *)parameters
      completeBlock:(YHCompleteBlock)completeBlock {
    [self postWithUrl:url parameters:parameters isEncryption:NO completeBlock:completeBlock];
}

- (void)postWithUrl:(NSString *)url
         parameters:(NSMutableDictionary *)parameters
       isEncryption:(BOOL)isEncryption
      completeBlock:(YHCompleteBlock)completeBlock {
    if (![self isExistenceNetwork]) {
        [MBProgressHUD showHUDMsg:@"请检查当前网络!" toView:nil];
        return;
    }
    __block XMResponseTip *tip = [[XMResponseTip alloc] init];
    // 请求地址
    NSString *requestUrl = [self getUrlStr:url];
    // 请求头
    NSMutableDictionary *headers = [self setRequestHeader];
    if (headers) {
        for (NSString *key in headers.allKeys) {
            [self.sessionManager.requestSerializer setValue:headers[key] forHTTPHeaderField:key];
        }
    }
    //    NSLog(@"请求头:%@",headers);
    NSMutableDictionary *dic = [self setParameters:parameters urlStr:requestUrl];
    __weak typeof(self) weakSelf = self;
    [self.sessionManager POST:requestUrl
                   parameters:dic
                      headers:headers
                     progress:^(NSProgress *_Nonnull uploadProgress) {
    }
                      success:^(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject) {
        [weakSelf postSuccess:responseObject task:task tip:tip completeBlock:completeBlock];
    }
                      failure:^(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull error) {
        [weakSelf postFailure:task error:error tip:tip completeBlock:completeBlock];
    }];
}

- (void)getWithUrl:(NSString *)url
        parameters:(NSDictionary *)parameters
     completeBlock:(YHCompleteBlock)completeBlock {
    if (![self isExistenceNetwork]) {
        [MBProgressHUD showHUDMsg:@"请检查当前网络!" toView:nil];
        return;
    }
    __block XMResponseTip *tip = [[XMResponseTip alloc] init];
    // 请求地址
    NSString *requestUrl = [self getUrlStr:url];
    __weak typeof(self) weakSelf = self;
    [self.sessionManager GET:requestUrl
                  parameters:parameters
                     headers:nil
                    progress:^(NSProgress *_Nonnull downloadProgress) {
    }
                     success:^(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject) {
        [weakSelf postSuccess:responseObject task:task tip:tip completeBlock:completeBlock];
    }
                     failure:^(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull error) {
        [weakSelf postFailure:task error:error tip:tip completeBlock:completeBlock];
    }];
}

- (void)uploadWithFileData:(NSData *)fileData
                       url:(NSString *)url
                parameters:(NSMutableDictionary *)parameters
                      name:(NSString *)name
                  fileName:(NSString *)fileName
                  mimeType:(NSString *)mimeType
                  progress:(void (^)(NSProgress *))progress
             completeBlock:(YHCompleteBlock)completeBlock {
    if (![self isExistenceNetwork]) {
        [MBProgressHUD showHUDMsg:@"请检查当前网络!" toView:nil];
        return;
    }
    __block XMResponseTip *tip = [[XMResponseTip alloc] init];
    // 请求地址
    NSString *requestUrl = [self getUrlStr:url];
    // 请求头
    NSMutableDictionary *headers = [self setRequestHeader];
    if (headers) {
        for (NSString *key in headers.allKeys) {
            [self.sessionManager.requestSerializer setValue:headers[key] forHTTPHeaderField:key];
        }
    }
    __weak typeof(self) weakSelf = self;
    [self.sessionManager POST:requestUrl
                   parameters:parameters
                      headers:headers
    constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
        [formData appendPartWithFileData:fileData name:name fileName:fileName mimeType:mimeType];
    }
                     progress:^(NSProgress *_Nonnull uploadProgress) {
        if (progress) { progress(uploadProgress); }
    }
                      success:^(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject) {
        [weakSelf postSuccess:responseObject task:task tip:tip completeBlock:completeBlock];
    }
                      failure:^(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull error) {
        [weakSelf postFailure:task error:error tip:tip completeBlock:completeBlock];
    }];
}

- (void)uploadWithFileUrl:(NSURL *)fileUrl
                      url:(NSString *)url
               parameters:(NSMutableDictionary *)parameters
                 progress:(void (^)(NSProgress *))progress
            completeBlock:(YHCompleteBlock)completeBlock {
    if (![self isExistenceNetwork]) {
        [MBProgressHUD showHUDMsg:@"请检查当前网络!" toView:nil];
        return;
    }
    __block XMResponseTip *tip = [[XMResponseTip alloc] init];
    // 请求地址
    NSString *requestUrl = [self getUrlStr:url];
    // 请求头
    NSMutableDictionary *headers = [self setRequestHeader];
    if (headers) {
        for (NSString *key in headers.allKeys) {
            [self.sessionManager.requestSerializer setValue:headers[key] forHTTPHeaderField:key];
        }
    }
    __weak typeof(self) weakSelf = self;
    [self.sessionManager POST:requestUrl
                   parameters:parameters
                      headers:headers
    constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
        [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];
    }
                     progress:^(NSProgress *_Nonnull uploadProgress) {
        if (progress) { progress(uploadProgress); }
    }
                      success:^(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject) {
        [weakSelf postSuccess:responseObject task:task tip:tip completeBlock:completeBlock];
    }
                      failure:^(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull error) {
        [weakSelf postFailure:task error:error tip:tip completeBlock:completeBlock];
    }];
}

#pragma mark - 请求成功数据处理
- (void)postSuccess:(id)responseObject
               task:(NSURLSessionDataTask *)task
                tip:(XMResponseTip *)tip
      completeBlock:(YHCompleteBlock)completeBlock {
    // 两种返回数据类型
    // NSDictionary *resposeJson = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil];
    NSDictionary *resultDict = responseObject;
    tip = [XMResponseTip mj_objectWithKeyValues:resultDict];
    NSDictionary *data = [resultDict safe_objectForKey:@"data"];
    if ([tip.code isEqualToString:@"200"]) {
        if ([data isKindOfClass:[NSDictionary class]]) {
            NSString *content = [data stringValueForKey:@"content" default:@""];
            NSString *signature = [data stringValueForKey:@"signature" default:@""];
            NSString *deWith2048Key = [YHRSAHelper decrypt:signature keyFilePath:[[NSBundle mainBundle] pathForResource:@"reponse_private_key.pem" ofType:nil] filePwd:nil];
            NSString *str = [YHAESHelper aesDecryptString:content publicKey:deWith2048Key];
            data = [str jsonValueDecoded];
            // 加载更多相关
            tip.loadMore = [[data safe_objectForKey:@"loadMore"] boolValue];
            tip.prevIndex = [[data safe_objectForKey:@"prevIndex"] stringValue];
        } else if ([data isKindOfClass:[NSNull class]]) {
            data = @{};
        }
    } else if ([tip.code isEqualToString:@"201"]) {
        // 响应成功, 无响应数据
        data = @{};
    } else if ([tip.code isEqualToString:@"300"]) {
        // 响应失败, 直接显示客户端错误信息
        data = @{};
//        NSLog(@"%@",resultDict);
        [MBProgressHUD hideHUD];
        [MBProgressHUD showHUDMsg:tip.message toView:nil];
    } else if ([tip.code isEqualToString:@"400"]) {
        // 响应失效, 令牌验证失败, 跳转登录
        data = @{};
        //NSLog(@"%@",resultDict);
        [MBProgressHUD hideHUD];
        [kNotificationCenter postNotificationName:kTokenExpire object:nil];
    } else if ([tip.code isEqualToString:@"500"]) {
        // 响应异常, 服务端程序异常信息, 不直接显示给用户
        data = @{};
        //NSLog(@"%@",resultDict);
        [MBProgressHUD hideHUD];
    } else {
        data = @{};
        //NSLog(@"%@",resultDict);
        [MBProgressHUD hideHUD];
    }
#if RELEASE
#else
    NSString *url = task.response.URL.absoluteString;
    NSString *param = [self.logUrlDic safe_objectForKey:url];
//    if (![url containsString:@"api/user/obtain"]) {
        NSLog(@"\n 请求地址:%@ \n 请求参数:%@ \n 请求头:%@ \n 请求结果:%@ \n", url, param ? param : @"", [self setRequestHeader], [data isKindOfClass:NSDictionary.class] ? (data.allKeys.count > 0 ? data : resultDict) : data);
//    }
    // 保存log到本地
    if ([tip.code isEqualToString:@"200"]) {
        [self saveLogResponse:data url:url param:param success:YES];
    } else if ([tip.code isEqualToString:@"201"]) {
        [self saveLogResponse:resultDict url:url param:param success:YES];
    } else {
        [self saveLogResponse:resultDict url:url param:param success:NO];
    }
#endif
    completeBlock(tip, data);
}

#pragma mark - 请求失败数据处理
- (void)postFailure:(NSURLSessionDataTask *)task
              error:(NSError *)error
                tip:(XMResponseTip *)tip
      completeBlock:(YHCompleteBlock)completeBlock {
    //失败回调
    if (error.code == NSURLErrorCancelled) { // 请求取消
        [tip setupVerifyInfoWithcode:kResultCodeErrorStr errorDesc:[NSString stringWithFormat:@"请求取消(%ld)", (long)error.code]];
    } else if (error.code == NSURLErrorTimedOut) { // 请求超时
        [tip setupVerifyInfoWithcode:kResultCodeErrorStr errorDesc:[NSString stringWithFormat:@"请求超时(%ld)", (long)error.code]];
    } else {
        [tip setupVerifyInfoWithcode:kResultCodeErrorStr errorDesc:[NSString stringWithFormat:@"服务器异常,请稍后再试!"]];
    }
    [MBProgressHUD hideHUD];
    [MBProgressHUD showHUDError:@"服务器异常,请稍后再试!" toView:nil];
#if RELEASE
#else
    NSString *url = task.response.URL.absoluteString;
    NSString *param = [self.logUrlDic safe_objectForKey:url];
    // 保存log到本地
    [self saveLogResponse:error.description url:url param:param success:NO];
    NSLog(@"\n 请求失败地址:%@ \n 请求参数:%@ \n", url, param ? param : @"");
    NSLog(@"\n %@  \n", error.description);
#endif
    completeBlock(tip, @{});
}

#pragma mark - 获取url
- (NSString *)getUrlStr:(NSString *)urlStr {
    NSString *serveHost = [kMMKV getStringForKey:kRequestUrlKey];
#if RELEASE
#else
    if (![NSString isEmpty:[kMMKV getStringForKey:kDebugRequestUrlKey]]) {
        serveHost = [kMMKV getStringForKey:kDebugRequestUrlKey];
    }
#endif
    NSString *urlString = [NSString stringWithFormat:@"%@%@", serveHost, urlStr];
    return urlString;
}

#pragma mark - 请求头
- (NSMutableDictionary *)setRequestHeader {
    NSMutableDictionary *header = @{
        @"appVersion": [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"],
        @"appName": @"XunMi",
        @"appOS": @"iOS",
        @"appChannel": @"iOS",
    }.mutableCopy;
    
    NSString *token = [kMMKV getStringForKey:kLoginToken];
    if (token.length > 0 && token != nil) {
        [header setObject:token forKey:@"appToken"];
    }
    return header;
}

#pragma mark - 底层参数等
- (NSMutableDictionary *)setParameters:(NSMutableDictionary *)parameters urlStr:(NSString *)urlStr {
    [parameters setValue:[NSDate xm_getCurrentTimeIntervalWithLenght:13] forKey:@"timestamp"];
//    NSInteger count = parameters.count;
//    NSString *str = [NSString stringWithFormat:@"%@?", urlStr];
    NSString *paramStr = [parameters jsonStringEncoded];
//    NSString *paramStr = @"";
//    for (int i = 0; i < count; i++) {
//        NSString *tmpStr = [NSString stringWithFormat:@"%@=%@&", parameters.allKeys[i], parameters.allValues[i]];
//        if (tmpStr && ![tmpStr isEqualToString:@""]) {
//            str = [str stringByAppendingString:tmpStr];
//            paramStr = [paramStr stringByAppendingString:tmpStr];
//        }
//    }
    //    NSLog(@"请求链接:=========================\n\n%@\n\n=========================", str);
    //    NSLog(@"请求参数:\n%@", parameters);
#if RELEASE
#else
    // 存到字典中
    [self.logUrlDic safeSetObject:[parameters jsonStringEncoded] forKey:urlStr];
#endif
    // 参数AES加密
    NSString *aesKey = [YHAESHelper getRandomNumberString];
    NSString *aesParamStr = [YHAESHelper aesEncryptString:paramStr publicKey:aesKey];
    // AESKey RSA加密
    NSString *requestPubKeyPath = [[NSBundle mainBundle] pathForResource:@"request_public_key.pem" ofType:nil];
    NSString *rsaStr = [YHRSAHelper encrypt:aesKey keyFilePath:requestPubKeyPath];
    
    // 组装成最终的请求参数
    NSMutableDictionary *paramDic = @{}.mutableCopy;
    [paramDic safeSetObject:aesParamStr forKey:@"content"];
    [paramDic safeSetObject:rsaStr forKey:@"signature"];
    if ([urlStr containsString:@"appstoreNotify"]) {
        NSLog(@"paramDic: %@", paramDic);
    }
    return paramDic;
}

- (void)saveLogResponse:(id _Nullable)response
                    url:(NSString *)url
                  param:(NSString *)param
                success:(BOOL)success {
    YHNetLogModel *logModel = [[YHNetLogModel alloc] init];
    if ([response isKindOfClass:[NSDictionary class]]) {
        logModel.response = [response jsonStringEncoded];
    } else if ([response isKindOfClass:[NSString class]]) {
        logModel.response = response;
    }
    logModel.url = url;
    logModel.param = param;
    logModel.date = [self getTimeString];
    logModel.success = success;
    [[YHNetLogManager sharedInstance] addLog:logModel];
    if (self.logUrlDic[url]) {
        [self.logUrlDic removeObjectForKey:url];
    }
}

- (NSString *)getTimeString {
    NSTimeInterval time = [[NSDate date] timeIntervalSince1970] * 1000;
    NSInteger day = floor(time);
    return [NSString stringWithFormat:@"%ld", day];
}

- (BOOL)isExistenceNetwork {
    BOOL isExistenceNetwork = YES;
    switch ([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus) {
        case AFNetworkReachabilityStatusUnknown:
            isExistenceNetwork = YES;
            break;
        case AFNetworkReachabilityStatusNotReachable:
            isExistenceNetwork = NO;
            break;
        case AFNetworkReachabilityStatusReachableViaWWAN:
            isExistenceNetwork = YES;
            break;
        case AFNetworkReachabilityStatusReachableViaWiFi:
            isExistenceNetwork = YES;
            break;
        default:
            break;
    }
    return isExistenceNetwork;
}

@end
